//Author:       Miguel Dominguez & Heath Cazeau
//Date:         3/9/2011
//Class:        Software Engineering
//Project:      Jaz Interpreter
//File:         Executor.cpp

#include <iostream>
#include <stack>
#include <string.h>
#include <stdio.h>
#include "MainEnvironment.h"
#include "LocalEnvironment.h"
#include "Executor.h"
#include "Instruction.h"
#include "InstructionSet.h"
#include <map>

using namespace operations;

void Executor::ExecuteInstructions()
{
    bool isBranching = false;
    Instruction * current = &this->mainEnvironment.LinkedList;
    this->LMem = &this->mainEnvironment.Memory;
    this->RMem = &this->mainEnvironment.Memory;

    while((*current).getKeyword().compare("halt") != 0)
    {
        string keyword = (*current).getKeyword();
        string argument = (*current).getArgument();

        if(keyword.compare("push")==0)
        {
            StackManipulation::push(this->dataStack, argument);
        }

        else if(keyword.compare("pop")==0)
        {
            StackManipulation::pop(this->dataStack);
        }

        else if(keyword.compare("rvalue")==0)
        {
            StackManipulation::rvalue(this->dataStack, *this->RMem, argument);
        }

        else if(keyword.compare("lvalue")==0)
        {
            StackManipulation::lvalue(this->dataStack, argument);
        }
                
        else if(keyword.compare(":=")==0)
        {
            StackManipulation::assign(this->dataStack, *this->LMem);
        }
        
        else if(keyword.compare("copy")==0)
        {
            StackManipulation::copy(this->dataStack);
        }
        
        else if(keyword.compare("gofalse")==0)
        {
            current = Branch::goFalse(this->dataStack, this->mainEnvironment.LabelLocations, argument, current);
            isBranching = true;
        }

        else if(keyword.compare("goto")==0)
        {
            current = Branch::goTo(this->mainEnvironment.LabelLocations,argument);
            isBranching = true;
        }

        else if(keyword.compare("gotrue")==0)
        {
            current = Branch::goTrue(this->dataStack, this->mainEnvironment.LabelLocations, argument, current);
            isBranching = true;
        }

        else if(keyword.compare("halt")==0)
        {
            current = Branch::halt();
            isBranching = true;
        }

        else if(keyword.compare("+")==0)
        {
            Arithmetic::add(this->dataStack);
        }

        else if(keyword.compare("-")==0)
        {
            Arithmetic::subtract(this->dataStack);
        }

        else if(keyword.compare("*")==0)
        {
            Arithmetic::multiply(this->dataStack);
        }

        else if(keyword.compare("/")==0)
        {
            Arithmetic::divide(this->dataStack);
        }

        else if(keyword.compare("div")==0)
        {
            Arithmetic::modulus(this->dataStack);
        }

        else if(keyword.compare("&")==0)
        {
            Logical::logicalAnd(this->dataStack);
        }

        else if(keyword.compare("!")==0)
        {
            Logical::logicalNot(this->dataStack);
        }

        else if(keyword.compare("|")==0)
        {
            Logical::logicalOr(this->dataStack);
        }

        else if(keyword.compare("<>")==0)
        {
            Comparison::notEqual(this->dataStack);
        }

        else if(keyword.compare("<=")==0)
        {
            Comparison::lessThanOrEqual(this->dataStack);
        }

        else if(keyword.compare(">=")==0)
        {
            Comparison::greaterThanOrEqual(this->dataStack);
        }

        else if(keyword.compare("<")==0)
        {
            Comparison::lessThan(this->dataStack);
        }

        else if(keyword.compare(">")==0)
        {
            Comparison::greaterThan(this->dataStack);
        }

        else if(keyword.compare("=")==0)
        {
            Comparison::equal(this->dataStack);
        }

        else if(keyword.compare("print")==0)
        {
            Output::print(this->dataStack);
        }

        else if(keyword.compare("show")==0)
        {
            Output::show(argument);
        }

        else if(keyword.compare("begin")==0)
        {
            LocalEnvironment newLocalEnv;
            if(EnvironmentStack.empty())
            {
                newLocalEnv.parentMemory = &(this->mainEnvironment.Memory);
            }

            else
            {
                newLocalEnv.parentMemory = &(EnvironmentStack.top().Memory);
            }

            EnvironmentStack.push(newLocalEnv);
            LMem = &(EnvironmentStack.top().Memory);
            RMem = EnvironmentStack.top().parentMemory;
        }

        else if(keyword.compare("call")==0)
        {
           // cout << EnvironmentStack.top().test << endl;
            LMem = &(EnvironmentStack.top().Memory);
            RMem = &(EnvironmentStack.top().Memory);
            EnvironmentStack.top().backToCallingFunction = (*current).getNextInstruction();
            current = this->mainEnvironment.LabelLocations[argument];
            isBranching = true;
        }

        else if(keyword.compare("return")==0)
        {
            current = EnvironmentStack.top().backToCallingFunction;
            isBranching = true;
            LMem = EnvironmentStack.top().parentMemory;
            RMem = &(EnvironmentStack.top().Memory);
        }

        else if(keyword.compare("end")==0)
        {
            LMem = EnvironmentStack.top().parentMemory;
            RMem = EnvironmentStack.top().parentMemory;
            EnvironmentStack.pop();
        }

        else
        {
            cout << "poop\n";
        }

        if(!isBranching)
        {
            current = (*current).getNextInstruction();
        }

        isBranching = false;
    }
}